// 容易理解
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;   // 网格最大尺寸
const int inf = 1e9 + 10; // 无穷大值

// 状态节点：记录当前位置和光线方向
struct Node {
  int x, y, f; // (x,y)为当前格子坐标，f为光线入射方向
};

string dir = "ABC";  // 三种镜子类型：A、B、C
string s[N];         // 存储网格中的镜子类型
vector<int> d[4][N]; // 距离数组：d[方向][行][列] 记录到达该状态的最小修改次数

// 方向数组：右(0)、下(1)、左(2)、上(3)
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};

// 计算光线经过镜子后的下一个状态
// 参数：当前坐标(x,y)，入射方向f，镜子类型c
// 输出：下一个坐标(nx,ny)，新的方向nf
void nxt(int x, int y, int f, char c, int &nx, int &ny, int &nf) {
  if (c == 'A') // A型镜子：光线直行，方向不变
    nf = f;
  else if (c == 'B')  // B型镜子：光线反射，方向变为(5-f)%4
    nf = (5 - f) % 4; // 等价于 (f+2)%4，即反向
  else                // C型镜子：光线反射，方向变为3-f
    nf = 3 - f;       // 等价于 (f+1)%4 或 (f+3)%4，取决于f的奇偶性
  nx = x + dx[nf];    // 计算下一个格子的x坐标
  ny = y + dy[nf];    // 计算下一个格子的y坐标
}

int main() {
  int n, m;
  cin >> n >> m;

  // 读入网格数据，索引从1开始
  for (int i = 1; i <= n; i++) {
    cin >> s[i];
    s[i] = ' ' + s[i]; // 在字符串前加空格，使索引从1开始
  }

  // 初始化距离数组为无穷大
  for (int i = 0; i <= n + 1; i++) {
    for (int k = 0; k <= 3; k++) {
      d[k][i].assign(m + 2, inf);
    }
  }

  // 初始状态：从(1,1)位置，方向向右(0)开始，修改次数为0
  d[0][1][1] = 0;

  // 使用双端队列进行01BFS
  deque<Node> q;
  q.clear();
  q.push_back({1, 1, 0}); // 初始状态入队

  int ans = inf; // 记录最终答案

  // 01BFS主循环
  while (!q.empty()) {
    // 从队头取出当前状态
    auto [x, y, f] = q.front();
    q.pop_front();

    int nx, ny, nf, dis;

    // 枚举三种可能的镜子类型
    for (auto c : dir) {
      // 计算光线经过当前格子（假设镜子类型为c）后的下一个状态
      nxt(x, y, f, c, nx, ny, nf);

      // 计算到达新状态的代价
      // 如果当前格子本来就是c型镜子，则不需要修改，代价为0
      // 否则需要修改镜子类型，代价为1
      if (s[x][y] == c)
        dis = d[f][x][y]; // 无需修改
      else
        dis = d[f][x][y] + 1; // 需要修改，代价+1

      // 检查是否到达目标位置：最后一行，第m+1列（网格右侧边界），方向向右
      if (nx == n && ny == m + 1 && nf == 0)
        ans = min(ans, dis); // 更新最小修改次数

      // 检查新位置是否越界
      if (nx == 0 || ny == 0 || nx > n || ny > m)
        continue;

      // 如果找到更短的路径到达新状态
      if (dis < d[nf][nx][ny]) {
        d[nf][nx][ny] = dis; // 更新距离

        // 01BFS核心：根据代价决定入队位置
        // 如果不需要修改镜子（代价为0），则放入队头（优先处理）
        // 如果需要修改镜子（代价为1），则放入队尾（稍后处理）
        if (s[x][y] == c)
          q.push_front({nx, ny, nf}); // 0代价，优先处理
        else
          q.push_back({nx, ny, nf}); // 1代价，稍后处理
      }
    }
  }

  cout << ans << endl;
  return 0;
}